#include "model/matrixtransformation.h"
#include <algorithm>

#define PI 3.141592654
#define RADIANS(x) x*PI/180

MatrixTransformation::MatrixTransformation() {
    coord data[4][4] {
        {1, 0, 0, 0},
        {0, 1, 0, 0},
        {0, 0, 1, 0},
        {0, 0, 0, 1}
    };

    this->setData(data);
}

MatrixTransformation::MatrixTransformation(const MatrixTransformation &m) {

    this->setData(m.data);
}

void MatrixTransformation::scale(coord x, coord y, coord z) {
    coord matrix[4][4] {
        {x, 0, 0, 0},
        {0, y, 0, 0},
        {0, 0, z, 0},
        {0, 0, 0, 1}
    };

    this->multiply(matrix);
}

void MatrixTransformation::translation(coord x, coord y, coord z) {
    coord matrix[4][4] {
        {1, 0, 0, x},
        {0, 1, 0, y},
        {0, 0, 1, z},
        {0, 0, 0, 1}
    };

    this->multiply(matrix);
}

void MatrixTransformation::setData(const coord (&data)[4][4]) {
    std::copy(&data[0][0], &data[0][0]+16, &this->data[0][0]);
}

void MatrixTransformation::multiply(coord (&input)[4][4]) {
    coord result[4][4];
    for ( unsigned int row = 0; row < 4; row++ )
        for ( unsigned int column = 0; column < 4; column++ ) {
            coord s = 0;
            for ( unsigned int inner = 0; inner < 4; inner++ )
                s += input[row][inner] * data[inner][column];
            result[row][column] = s;
        }
    this->setData(result);
}

void MatrixTransformation::rotationX(coord angle) {
    coord matrix[4][4] {
        {1, 0, 0, 0},
        {0, cos(RADIANS(angle)), -sin(RADIANS(angle)), 0},
        {0, sin(RADIANS(angle)), cos(RADIANS(angle)), 0},
        {0, 0, 0, 1}
    };

    this->multiply(matrix);
}

void MatrixTransformation::rotationY(coord angle) {
    coord matrix[4][4] {
        {cos(RADIANS(angle)), 0, sin(RADIANS(angle)), 0},
        {0, 1, 0, 0},
        {-sin(RADIANS(angle)),0, cos(RADIANS(angle)), 0},
        {0, 0, 0, 1}
    };

    this->multiply(matrix);
}

void MatrixTransformation::rotationZ(coord angle) {
    coord matrix[4][4] {
        {cos(RADIANS(angle)), -sin(RADIANS(angle)),0, 0},
        {sin(RADIANS(angle)), cos(RADIANS(angle)), 0, 0},
        {0, 0, 1, 0},
        {0, 0, 0, 1}
    };

    this->multiply(matrix);
}

const coord* MatrixTransformation::operator [](unsigned int i) const {
    return this->data[i];
}

